from stream import Stream
from source import Source
import defs.exception as exception
import os, os.path

class FileStream(Stream, Source):
    """
    Stream based on file.
    """
    
    def __init__(self, path, readonly = False, writeonly = False):
        assert isinstance(path, str)
        self.filepath = path
        #self.fileaccess = {(False, False):"r+", (False, True):"r+", (True, False):"r"}[(readonly, writeonly)]
        self.fileaccess = readonly and "rb" or "rb+"
        if not os.path.exists(path):
            self.fileaccess = "wb+"
        self.filero = readonly
        self.filewo =writeonly
        self.file = None

    def open(self):
        try:
            self.file = open(self.filepath,  self.fileaccess)
        except IOError:
            raise exception.BlaIOError("file %s opening with access %s fail." % (self.filepath, self.fileaccess))

    def write(self, data):
        if self.filero:
            raise exception.BlaIOError("can not read.")
        if self.file == None:
            raise exception.BlaIOError("Stream not opened.")
        self.file.write(data)
    
    def read(self, size = -1):
        assert size >= -1;
        if self.filewo:
            raise exception.BlaIOError("can not write.")
        if self.file == None:
            raise exception.BlaIOError("Source not opened.")
        if size == -1:
            return self.file.read()
        else:
            return self.file.read(size)
        
    def close(self):
        self.file.flush()
        self.file.close()
        self.file = None
    
    def addOutBranch(self, outstream):
        pass
        
    def tell(self):
        assert self.file
        return self.file.tell()
        
    def seek(self, offset, whence = os.SEEK_SET):
        assert self.file
        self.file.seek(offset, whence)
        
    def getSize(self):
        pos = self.file.tell()
        self.file.seek(0, os.SEEK_END)
        size = self.file.tell()
        self.file.seek(pos, os.SEEK_SET)
        return size
